//<<<+++OPENSOURCE
//<<<+++OPENSOURCE_LICENSE
/**
 * @addtogroup FPDFAPI
 * @{
 */

/**
 * @file
 * @brief PDF page and form definitions. 
 */
//<<<+++OPENSOURCE_MUST_BEGIN
#ifndef _FPDF_PAGE_
#define _FPDF_PAGE_

// Make use of basic PDF object data structure defined in parser module.
#ifndef _FPDF_PARSER_
#include "fpdf_parser.h"
#endif

// Make use of PDF resources (color/font/image, etc.) definition. 
#ifndef _FPDF_RESOURCE_
#include "fpdf_resource.h"
#endif

#ifndef _FX_DIB_H_
#include "../fxge/fx_dib.h"
#endif
//<<<+++OPENSOURCE_MUST_END

// classes defined in this header.
class CPDF_PageObjects;
class CPDF_Page;
class CPDF_Form;
class CPDF_ParseOptions;

// classes referred by this header.
class CPDF_PageObject;
class CPDF_PageRenderCache;
class CPDF_StreamFilter;
class CPDF_AllStates;
class CPDF_ContentParser;
class CPDF_StreamContentParser;
class CPDF_ResourceNaming;

//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
#ifndef _FXM_OPENSOURCE_
class CPDF_PageObjectsCache;
#endif
//<<<+++OPENSOURCE_END

#ifndef _FXM_OPENSOURCE_
//<<<+++OPENSOURCE_MUST_BEGIN LIC==FOXIT
#ifndef PDF_USE_PAGECACHE_
//#define PDF_USE_PAGECACHE_
#endif
//<<<+++OPENSOURCE_MUST_END
#endif

/**
 * @name Transparency attribute flags for a page object group (form or page).
 */
/*@{*/

/** @brief Whether a transparency group is present. */
#define PDFTRANS_GROUP			0x0100
/** @brief Whether a transparency group is isolated. For isolated groups, a separate level device is required. */
#define PDFTRANS_ISOLATED		0x0200
/** @brief Whether a transparency group is knockout. For non-knockout groups, composition is required for all objects inside. */
#define PDFTRANS_KNOCKOUT		0x0400

/*@}*/

/**
 * @name PDF content-parsing state.
 */
/*@{*/

/** @brief Not parsed. */
#define PDF_CONTENT_NOT_PARSED	0
/** @brief Parsing. */
#define PDF_CONTENT_PARSING		1
/** @brief Parsed. */
#define PDF_CONTENT_PARSED		2

/*@}*/

/** @brief Collection of page objects. Can be used for pages or forms. */
class CPDF_PageObjects : public CFX_Object
{
public:
	/**
	 * Construct an empty collection of page objects.
	 *
	 * @param[in] bReleaseMembers		Whether the collection takes charge of releasing of page objects.
	 */
	CPDF_PageObjects(FX_BOOL bReleaseMembers = TRUE);
	/** The destructor. */
	~CPDF_PageObjects();

	/**
	 * @name Parse content and build object list.
	 */
	/*@{*/
	
	/**
	 * Continue parsing.
	 *
	 * @param[in] pPause		The user-supplied pause object. 
	 */
	void				ContinueParse(IFX_Pause* pPause);
	/** Get the current parsing state. #PDF_CONTENT_NOT_PARSED, #PDF_CONTENT_PARSING, or #PDF_CONTENT_PARSED. */
	int					GetParseState() const { return m_ParseState; }
	/** Check whether the content has been parsed into page objects. */
	FX_BOOL				IsParsed() const { return m_ParseState == PDF_CONTENT_PARSED; }
	/** Estimate the amount of parse progress. */
	int					EstimateParseProgress() const;

	/*@}*/

	/**
	 * @name Access the object list.
	 */
	/*@{*/

	/** Get the position of the first page object. */
	FX_POSITION			GetFirstObjectPosition() const { return m_ObjectList.GetHeadPosition(); }
	/** Get the position of the last page object. */
	FX_POSITION			GetLastObjectPosition() const { return m_ObjectList.GetTailPosition(); }
	/**
	 * Get the current object and move to next position.
	 *
	 * @param[in,out] pos		It input the current position, and receives the next position.
	 * @return A page object.
	 */
	CPDF_PageObject*	GetNextObject(FX_POSITION& pos) const { return (CPDF_PageObject*)m_ObjectList.GetNext(pos); }
	/**
	 * Get the current object and move to previous position.
	 *
	 * @param[in,out] pos		It input the current position, and receives the previous position.
	 * @return A page object.
	 */
	CPDF_PageObject*	GetPrevObject(FX_POSITION& pos) const { return (CPDF_PageObject*)m_ObjectList.GetPrev(pos); }
	/**
	 * Get an object at specified position.
	 *
	 * @param[in] pos			Specified the position of the page object..
	 * @return A page object.
	 */
	CPDF_PageObject*	GetObjectAt(FX_POSITION pos) const { return (CPDF_PageObject*)m_ObjectList.GetAt(pos); }
	/** Get the count of page objects in the collection. */
	FX_DWORD			CountObjects() const { return m_ObjectList.GetCount(); }
	/**
	 * Get the zero-based page object index in the object array.
	 *
	 * @param[in] pObj			The page object pointer.
	 * @return The zero-based index of the page object.
	 */
	int					GetObjectIndex(CPDF_PageObject* pObj) const;
	/**
	 * Get an object by a zero-based page object index.
	 *
	 * @param[in] index			Specify the zero-based index of the page object.
	 * @return A page object.
	 */
	CPDF_PageObject*	GetObjectByIndex(int index) const;

	/*@}*/
    
	/**
	 * @name Modify object list. 
	 */
	/*@{*/

    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * Replace a page object with a new page object.
	 *
	 * @param[in] pos			Specify the position of the page object to be replaced.
	 * @param[in] pNewObject	The input new page object.
	 */
	void				ReplaceObject(FX_POSITION pos, CPDF_PageObject* pNewObject);
    //<<<+++OPENSOURCE_END
	
	/**
	 * Insert a page object. To insert before all objects, use NULL for posInsertAfter.
	 *
	 * @param[in] posInsertAfter	Specify the position to insert after.
	 * @param[in] pNewObject		the input new page object.
	 * @return The position of inserted page object.
	 */
	FX_POSITION			InsertObject(FX_POSITION posInsertAfter, CPDF_PageObject* pNewObject);
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * Remove a page object.
	 *
	 * @param[in] pos			Specify the position of the page object to be removed.
	 */
	void				RemoveObject(FX_POSITION pos);
	/**
	 * Move a page object from a position to another position.
	 *
	 * @param[in] pos			The original position of the page object.
	 * @param[in] newPosAfter	The new position to move after.
	 * @return The new position of the page object.
	 */
	FX_POSITION			MoveObject(FX_POSITION pos, FX_POSITION newPosAfter);

	/*@}*/

	/** Output debug information. for debug only: list all page objects. */
	void				DebugOutput(FX_LPCSTR filename) const;
    //<<<+++OPENSOURCE_END
	/**
	 * Transform all objects.
	 *
	 * @param[in] matrix		The input transform matrix.
	 */
	void				Transform(const CFX_AffineMatrix& matrix);
    
	/**
	 * Check whether this object list needs background alpha channel to render.
	 * If it's TRUE, then the application should better use ARGB device to render it,
	 * otherwise the objects may need more time to render.
	 * Please call this function after the page has been parsed.
	 */
	FX_BOOL				BackgroundAlphaNeeded() const { return m_bBackgroundAlphaNeeded; }

	/** Calculate the bounding box of all page objects in the collection. */
	CFX_FloatRect		CalcBoundingBox() const;

	/** The page dictionary or form stream dictionary. */
	CPDF_Dictionary*	m_pFormDict;
	/** For form only: the form stream. */
	CPDF_Stream*		m_pFormStream;

	/** The PDF document. */
	CPDF_Document*		m_pDocument;
	/** The page resources dictionaries inheritable. */
	CPDF_Dictionary*	m_pPageResources;
	/** Resources dictionary for this object list. */
	CPDF_Dictionary*	m_pResources;
	/** The bounding box. in page or form space. */
	CFX_FloatRect		m_BBox;

	/** Transparency flags. */
	int					m_Transparency;
    
	//////////////////////////////////////////////////////////////////////////////////////////////////
	//
	/** Functions implemented in EDIT module */
	//
	//////////////////////////////////////////////////////////////////////////////////////////////////
    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * Add a resource to current object list. Return the resource name.
	 * Will try to use an existing resource first, if available.
	 * Caller should not release the result resource object, which may be same as the input object.
	 * The input object can be an external object (which comes from another document, or archive),
	 * in this case, the object mapping should be specified.
	 *
	 * @param[in] pResourceObj			The input resource object.
	 * @param[in] pObjMapping			The input object mapping from object number to object pointer.
	 * @param[in] szType				The resource type name.
	 * @param[out] pResObj				It receives the result resource object.
	 * @return The resource name.
	 */
	CFX_ByteString		RealizeResource(CPDF_Object* pResourceObj, CFX_MapPtrToPtr* pObjMapping, 
							const FX_CHAR* szType, CPDF_Object** pResObj);

	/**
	 * @name Find matching resource in resource dictionary. May create new resource name if not found. 
	 */
	/*@{*/

	/**
	 * Find a resource name of specified color space.
	 *
	 * @param[in] pCS		The input color space.
	 * @return The resource name of the color space.
	 */
	CFX_ByteString		FindCSName(CPDF_ColorSpace* pCS);
	/**
	 * Find a resource name of specified font.
	 *
	 * @param[in] pFont		The input font.
	 * @return The resource name of the font.
	 */
	CFX_ByteString		FindFontName(CPDF_Font* pFont);

	/*@}*/

	/** For resource naming. */
	CPDF_ResourceNaming*	m_pResourceNaming;
    //<<<+++OPENSOURCE_END
protected:
	friend class		CPDF_ContentParser;
	friend class		CPDF_StreamContentParser;
	friend class		CPDF_AllStates;

    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * Add form objects.
	 *
	 * @param[in] pDocument			The PDF document. Required.
	 * @param[in] pPageResources	The resources in the page. Optional.
	 * @param[in] pStream			Content stream. Required.
	 * @param[in] pParentMatrix		The parent transform matrix. Optional.
	 * @param[in] pGraphicStates	Current graphic states. Optional.
	 */
	int					AddFormObjects(
							CPDF_Document* pDocument,
							CPDF_Dictionary* pPageResources,
							CPDF_Stream* pStream,
							CFX_AffineMatrix* pParentMatrix,
							CPDF_AllStates* pGraphicStates
						);
    //<<<+++OPENSOURCE_END

	/** The page object list. */
	CFX_PtrList			m_ObjectList;
	/** Whether this object list needs background alpha channel to render. */
	FX_BOOL				m_bBackgroundAlphaNeeded;
	/** Whether member objects should be deleted when this object destroyed. */
	FX_BOOL				m_bReleaseMembers;

	void				LoadTransInfo();
    
    void                ClearCacheObjects();

	/** The content parser. */
	CPDF_ContentParser*	m_pParser;
	/** The parsing state. */
	FX_BOOL				m_ParseState;

#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	CPDF_PageObjectsCache* m_pPageObjectsCache;
	friend class CPDF_PageObjectsCache;
	//<<<+++OPENSOURCE_END
#endif

};

/** @brief PDF page class. */
class CPDF_Page : public CPDF_PageObjects, public CFX_PrivateData
{
public:
	/** Default constructor. */
	CPDF_Page();
	/** The destructor. */
	~CPDF_Page();

	/**
	 * Construct a page. For saving memory, the page caching feature can be disabled, then
	 * images and masks used in page rendering won't be cached. Of course this will affect the speed.
	 *
	 * @param[in] pDocument		The PDF document.
	 * @param[in] pPageDict		The page dictionary.
	 * @param[in] bPageCache	Whether images and masks used in page rendering will be cached or not.
	 */
	void				Load(CPDF_Document* pDocument, CPDF_Dictionary* pPageDict, FX_BOOL bPageCache = TRUE);

	/**
	 * Start parsing the page. If pausing is enabled, application should check current parsing state
	 * after this function returns. If parsing not finished, ContinueParse() should be called.
	 *
	 * @param[in] pOptions		The parser options.
	 */
	void				StartParse(CPDF_ParseOptions* pOptions = NULL, FX_BOOL bReParse = FALSE);

	/**
	 * Parse all contents.
	 *
	 * @param[in] pOptions		The parser options.
	 */
	void				ParseContent(CPDF_ParseOptions* pOptions = NULL, FX_BOOL bReParse = FALSE);

	/**
	 * Build a matrix from PDF user space to targeted device space, according to metrics info
	 * (top-left position and widht-height size) provided in device space.
	 *
	 * @param[out] matrix		It receives the transform matrix from PDF user space to targeted device space.
	 * @param[in] xPos			The x-coordinate of the top-left position in the device space.
	 * @param[in] yPos			The y-coordinate of the top-left position in the device space.
	 * @param[in] xSize			The x-direction size in the device space.
	 * @param[in] ySize			The y-direction size in the device space.
	 * @param[in] iRotate		The rotation degrees. 
	 */
	void				GetDisplayMatrix(CFX_AffineMatrix& matrix, int xPos, int yPos, 
								int xSize, int ySize, int iRotate) const;

	/** Get the page width in user space. */
	FX_FLOAT			GetPageWidth() const { return m_PageWidth; }
	/** Get the page height in user space. */
	FX_FLOAT			GetPageHeight() const { return m_PageHeight; }

	/** Get the page bounding box in user space. */
	CFX_FloatRect		GetPageBBox() const { return m_BBox; }
	/** Get the page matrix. */
	const CFX_AffineMatrix&	GetPageMatrix() const  { return m_PageMatrix; }

	/**
	 * Get an inheritable attribute value.
	 *
	 * @param[in] name			The attribute(entry) name.
	 * @return The attribute value.
	 */
	CPDF_Object*		GetPageAttr(FX_BSTR name) const;

	/**
	 * @name Get associated data maintained by other FPDFAPI modules. 
	 */
	/*@{*/

	/** Get render cache. for RENDER module. */
	CPDF_PageRenderCache*	GetRenderCache() const { return m_pPageRender; }
	/** Clear render cache. */
	void				ClearRenderCache();

	/*@}*/

    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** The lock object. */
	CFX_LockObject		m_PageLock;
    //<<<+++OPENSOURCE_END

protected:
	friend class		CPDF_ContentParser;

	/** The page width. in user space. pre-rotated. */
	FX_FLOAT			m_PageWidth;
	/** The page height. in user space. pre-rotated. */
	FX_FLOAT			m_PageHeight;
	/** Page matrix by crop-box clipping and initial rotate. */
	CFX_AffineMatrix	m_PageMatrix;
	/** Any data used by the RENDER module. */
	CPDF_PageRenderCache*	m_pPageRender;
};

/** @brief Page parsing options. */
class CPDF_ParseOptions : public CFX_Object
{
public:
	/** Default constructor. */
	CPDF_ParseOptions();

	/** Only text object is parsed into object list. */
	FX_BOOL				m_bTextOnly;
	/** Load marked content (including foxit tag) information. */
	FX_BOOL				m_bMarkedContent;
	/** Generate CPDF_FormObject for form. */
	FX_BOOL				m_bSeparateForm;
	/**
	 * Decode inline image for better performance.
	 * This should be disabled for PDF Editor, to keep the result file size smaller.
	 */
	FX_BOOL				m_bDecodeInlineImage;
#if !defined(_FXM_OPENSOURCE_) && defined(PDF_USE_PAGECACHE_)
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** Whether use pageobjects cache, 0 = do not use, 1 = use a normal cache, 2 = use a grow only cache(faster but takes much more memory). */
	FX_UINT32			m_nUsePageObjectsCache;
	//<<<+++OPENSOURCE_END
#endif
};

/** @brief PDF form class. */
class CPDF_Form : public CPDF_PageObjects
{
public:
	/**
	 * Construct from a from stream.
	 *
	 * @param[in] pDocument			The PDF document.
	 * @param[in] pPageResources	The page resources.
	 * @param[in] pFormStream		The form stream.
	 */
	CPDF_Form(CPDF_Document* pDocument, CPDF_Dictionary* pPageResources, CPDF_Stream* pFormStream, CPDF_Dictionary* pParentResources = NULL);
	/** The destructor. */
	~CPDF_Form();

	/**
	 * Start parsing.
	 *
	 * @param[in] pGraphicStates		The current graphics states.
	 * @param[in] pParentMatrix			Matrix from form object to parent page/form. Optional.
	 * @param[in] pType3Char			Used only when parsing Type3 character forms.
	 * @param[in] pOptions				Parsing options.
	 * @param[in] level					Recusive level. 0 for default.
	 */
	void				StartParse(CPDF_AllStates* pGraphicStates,  CFX_AffineMatrix* pParentMatrix,
							CPDF_Type3Char* pType3Char, CPDF_ParseOptions* pOptions, int level = 0);

	/**
	 * Parse all contents.
	 *
	 * @param[in] pGraphicStates		The current graphics states.
	 * @param[in] pParentMatrix			Matrix from form object to parent page/form. Optional.
	 * @param[in] pType3Char			Used only when parsing Type3 character forms.
	 * @param[in] pOptions				Parsing options.
	 */
	void				ParseContent(CPDF_AllStates* pGraphicStates, CFX_AffineMatrix* pParentMatrix,
							CPDF_Type3Char* pType3Char, CPDF_ParseOptions* pOptions, int level = 0);
	/** Clone a form. */
	CPDF_Form*			Clone() const;
};
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
/** @brief Progressive text extractor for quick search.
 * Get a unicode string from a page quickly by directly parsing content stream. The returned string
 * might not be accurate but at least can be used to quickly check if a pattern can possibly be found
 * in the page.
 */
class CPDF_QuickTextExtractor : public CFX_Object
{
public:
	/** 
	 * Constructor.
	 *
	 * @param[in] pDocument		The document
	 */
	CPDF_QuickTextExtractor(CPDF_Document* pDoc);
	~CPDF_QuickTextExtractor();

	/** Start extracting for a page. A quick text extractor can be reused for more than one pages.
	 * @param[in] pPageDict		Page dictionary
	 * @return FALSE for extracting finished, TRUE for need to continue
	 */
	FX_BOOL				StartPage(CPDF_Dictionary* pPageDict);

	/** Continue extracting the current page.
	 * @param[out] result	The result buffer receiving extracted Unicode string
	 * @param[in] pPause	Pause structure.
	 * @return FALSE for extracting finished, TRUE for need to continue
	 */
	FX_BOOL				Continue(CFX_WideTextBuf& result, IFX_Pause* pPause);

private:
	CPDF_Document*		m_pDocument;
	class CPDF_QuickTextParser*	m_pParser;
	class CPDF_QuickFontCache*	m_pFontCache;
};
//<<<+++OPENSOURCE_END

//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
class CPDF_PageContentGenerate : public CFX_Object
{
public:
    CPDF_PageContentGenerate(CPDF_Page* pPage);
    ~CPDF_PageContentGenerate();
    
    FX_BOOL InsertPageObject(CPDF_PageObject* pPageObject);
    void GenerateContent();
    void TransformContent(CFX_Matrix& matrix);
    
protected:
    void            ProcessImage(CFX_ByteTextBuf& buf, CPDF_ImageObject* pImageObj);
    void            ProcessForm(CFX_ByteTextBuf& buf, FX_LPCBYTE data, FX_DWORD size, CFX_Matrix& matrix);
    CFX_ByteString  RealizeResource(CPDF_Object* pResourceObj, const FX_CHAR* szType);

private:
    CPDF_Page*      m_pPage;
    CPDF_Document*  m_pDocument;
    CFX_PtrArray    m_pageObjects;
};
//<<<+++OPENSOURCE_END

//<<<+++OPENSOURCE_MUST_BEGIN
#endif
//<<<+++OPENSOURCE_MUST_END
/** @} */


